package com.je.wf.wfExecutor;

import com.je.core.constants.push.PushAct;
import com.je.core.constants.push.PushType;
import com.je.core.service.MetaService;
import com.je.core.service.PCServiceTemplate;
import com.je.core.util.SpringContextHolder;
import com.je.portal.service.PortalManager;
import net.sf.ehcache.util.NamedThreadFactory;
import org.jbpm.pvm.internal.env.EnvironmentFactory;
import org.jbpm.pvm.internal.env.EnvironmentImpl;
import org.jbpm.pvm.internal.processengine.SpringProcessEngine;
import org.jbpm.pvm.internal.task.TaskImpl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.*;

public class WfExecutorService {

    private static final int EXECUTOR_KEEP_ALIVE_TIME = 60000;
    private static final int EXECUTOR_MAXIMUM_POOL_SIZE = Math.min(10, Runtime.getRuntime().availableProcessors());
    private static final int EXECUTOR_CORE_POOL_SIZE = 5;

    private volatile static ExecutorService wfExecutorService;

    private WfExecutorService() {
    }

    public static ExecutorService getWfExecutorService() {
        if (wfExecutorService == null) {
            synchronized (WfExecutorService.class) {
                if (wfExecutorService == null) {
                    wfExecutorService = new ThreadPoolExecutor(EXECUTOR_CORE_POOL_SIZE, 15, EXECUTOR_KEEP_ALIVE_TIME,
                            TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), new NamedThreadFactory("Cache Executor Service"));
                }
            }
        }
        return wfExecutorService;
    }

    public static Map<String, Object> getPreapprovCount(String sql) {
        Map<String, Object> map = new HashMap<>();
        wfExecutorService = getWfExecutorService();
        Future future = wfExecutorService.submit((Callable<Object>) () -> {
            MetaService metaService = SpringContextHolder.getBean(MetaService.class);
            long count = metaService.countBySql(sql);
            map.put("count", count);
            return map;
        });
        map.put("future", future);
        return map;
    }

    public static Map<String, Object> getOwnerCount(String sql, Map<String, Object> params) {
        Map<String, Object> map = new HashMap<>();
        wfExecutorService = getWfExecutorService();
        Future future = wfExecutorService.submit((Callable<Object>) () -> {
            PCServiceTemplate pcServiceTemplate = SpringContextHolder.getBean(PCServiceTemplate.class);
            map.put("count", pcServiceTemplate.countBySql(sql, params));
            return map;
        });
        map.put("future", future);
        return map;
    }

    public static Map<String, Object> getListAndCount(String sql, Map<String, Object> params) {
        Map<String, Object> map = new HashMap<>();
        wfExecutorService = getWfExecutorService();
        Future future = wfExecutorService.submit((Callable<Object>) () -> {
            PCServiceTemplate pcServiceTemplate = SpringContextHolder.getBean(PCServiceTemplate.class);
            List<TaskImpl> taskImpls = (List<TaskImpl>) pcServiceTemplate.queryBySql(sql, params, TaskImpl.class);
            map.put("list", taskImpls);
            map.put("count", new Long(taskImpls.size()));
            return map;
        });
        map.put("future", future);
        return map;
    }

    public static Map<String, Object> getListLimit(String sql, Map<String, Object> params, int start, int limit) {
        Map<String, Object> map = new HashMap<>();
        wfExecutorService = getWfExecutorService();
        Future future = wfExecutorService.submit((Callable<Object>) () -> {
            PCServiceTemplate pcServiceTemplate = SpringContextHolder.getBean(PCServiceTemplate.class);
            SpringProcessEngine processEngine = SpringContextHolder.getBean(SpringProcessEngine.class);
            EnvironmentImpl env = ((EnvironmentFactory) processEngine).openEnvironment();
            try {
                List<TaskImpl> taskImpls = (List<TaskImpl>) pcServiceTemplate.queryBySql(sql, params, start, limit, TaskImpl.class);
                map.put("list", taskImpls);
            } finally {
                env.close();
            }
            return map;
        });
        map.put("future", future);
        return map;
    }

    public static void commitPushMsg(Set<String> portalUserIds) {
        wfExecutorService = getWfExecutorService();
        PortalManager portalManager = SpringContextHolder.getBean(PortalManager.class);
        wfExecutorService.execute(() -> {
            for (String userId : portalUserIds) {
                portalManager.push(userId, new String[]{PushType.WF}, new String[]{PushAct.ALL});
            }
        });
    }
}
